
package message;

import java.rmi.RemoteException;
import java.util.Map;
import node.Node;

/**
 * It is a runable that runs a new task on the queue which is maintained by Executorservice.threadpool
 *  where the thread pool size is 1.Therefore it forces it to act like a queue.

 * 
 * @author TCSS 558 Team 6
 * @version Spring 2013
 */

public class MessageProcessor implements Runnable
{
  /** It stores the result. */
  Map<String, Message> my_results_table;
  
  /** This is the message. */
  Message my_message;
  
  /** The node which is being dealt with.  */
  private Node my_node;
  
  /**   */
  private Object my_monitor;
  
  
  /**  */
  public MessageProcessor(Map<String, Message> my_results_table2, Message the_message,
                         Node node, Object the_monitor)
  {
    my_results_table = my_results_table2;
    my_message = the_message;
    my_node = node;
    my_monitor = the_monitor;
  }

  @Override
  /**
   * 
   */
  public void run()
  {

    try
    {

      // block 1

      if (my_message.isFoundTarget() && my_node.getMyID() == my_message.getDestination())
      {
        // if i am the original node
        if (my_message.getType().equals(MessageType.ADD_NODE))
        {
          System.out.println("Node " + my_node.getMyID() +
                             " got the virtual node data from somewhere");
          // here i have to add the virtual nodes that predecessor sent to my
          // virtual nodes
          my_node.unloadVirtualNodeData(my_message);
        }
        else
        { // get the message
          System.out.println("Node " + my_node.getMyID() + "Got the response from " +
                             my_message.getOrigin());
          my_results_table.put(my_message.getMyId(), my_message);
          synchronized (my_monitor)
          {
            my_monitor.notifyAll();
          }
        }

        // block 2

      }
      else if (!my_message.isFoundTarget() &&
               my_node.containVirtual(my_message.getDestination()))
      {
        // if i am the destination node => logic for processing data here.
        my_message.setFoundTarget(true);
        my_message.setIntermediate(my_message.getTarget());
        System.out.println("At node: " + my_node.getMyID() +
                           " | Processing message: reached the destination actual node");
        // different behavior based on the different message type => add data
        // to the message here.
        boolean sendmessage = true;

        switch (my_message.getType())
        {
          case ADD_NODE:
            System.out.println("Node " + my_node.getMyID() +
                               " reached the destination - sending nodes back " +
                               my_message.getType().toString());
            my_node.loadVirtualNodeData(my_message);
            break;
          case ADD_NODE_ACK:
            System.out.println("Node " + my_node.getMyID() +
                               " reached the destination - deleting nodes " +
                               my_message.getType().toString());
            my_node.deleteTransferedVirtualNodes(my_message);
            sendmessage = false;
            break;
          case DELETE_NODE:
            my_node.unloadVirtualNodeData(my_message);
            // unloadVirtualNodeData handles sending the acknowledgement
            // message.
            System.out.println("Node " + my_node.getMyID() +
                               " has recieved the message and virtual nodes");
            sendmessage = false; // no message loop - one way message only!
            break;
          case DELETE_NODE_ACK:
            System.out.println("Node " + my_node.getMyID() +
                         " got an acknowledgement to leave from somewhere - leaving the ring! bye!");
            my_node.initializeShutDown(my_message);
            break;
          case UPDATE_CHANNELS:
            if (my_message.getDestination() == my_node.getMyID())
            {
              my_node.reinitializeChannels();
              System.out.println("Node " +
                           my_node.getMyID() +
                           "reached destination - no need" +
                           " to updating channels for actual node - not sending return message" +
                           my_message.getType().toString());
//              my_node.log();
            }
            System.out.println("Node " + my_node.getMyID() + "reached destination - no need " +
                               "to update virtual nodes - not sending return message" +
                               my_message.getType().toString());
            sendmessage = false;
            break;
          default:
            my_node.processRequest(my_message);
            System.out.println("Node " + my_node.getMyID() + "The value is " +
                               my_message.getValue());
            break;
        }

       
        if (sendmessage)
        {
          my_node.send_message(my_message);
        }

        // block 3

      }
      else
      {                                     // if i am intermediate node send out message.
        my_node.send_message(my_message);
      }
    }
    catch (RemoteException e)
    {
     
      e.printStackTrace();
    }
  }

}
